package com.ideal.core.builder;

import com.ideal.core.constant.Constant;
import com.ideal.core.constant.Type;
import com.ideal.core.table.TableClassConverter;
import com.ideal.utils.Empty;
import com.ideal.utils.HanyuPinyinHelper;
import com.ideal.utils.StringUtils;
import com.ideal.utils.TableBuilder;
import freemarker.ext.beans.BeansWrapper;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateHashModel;

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.net.URL;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

public class ClassBuilder{
    /**
     * 基础类名
     */
    private static String BASE_CLASS_NAME = null;
    private static String TABLE_NAME = null;
    private static String BASE_PACKAGE = null;
    /**
     * 根据类型拼接包名
     * @return
     */
    public static String packageName(Type type){
        StringBuilder basePackage = new StringBuilder(Constant.PACKAGE+Constant.SPACE+ClassBuilder.BASE_PACKAGE);
        switch (type){
            case DOMAIN:basePackage.append(Constant.DOMAIN_PACKAGE+Constant.CLOSE);break;
            case DAO:basePackage.append(Constant.DAO_PACKAGE+Constant.CLOSE);break;
            case DAO_IMPL:basePackage.append(Constant.DAO_IMPL_PACKAGE+Constant.CLOSE);break;
            case SERVICE:basePackage.append(Constant.SERVICE_PACKAGE+Constant.CLOSE);break;
            case SERVICE_IMPL: basePackage.append(Constant.SERVICE_IMPL_PACKAGE+Constant.CLOSE);break;
            case CONTROLLER:basePackage.append(Constant.CONTROLLER_PACKAGE+Constant.CLOSE);break;
            default: basePackage.append("");
        }
        return basePackage.toString();
    }


    /**
     * 根据类型拼接类名
     * @return
     */
    public static String className(Type type){
        switch (type){
            case DOMAIN:return BASE_CLASS_NAME+Constant.DOMAIN_CLASSNAME;
            case DAO: return Constant.PREFIX+BASE_CLASS_NAME+Constant.DAO_CLASSNAME;
            case DAO_IMPL: return BASE_CLASS_NAME+Constant.DAO_IMPL_CLASSNAME;
            case SERVICE:  return Constant.PREFIX+BASE_CLASS_NAME+Constant.SERVICE_CLASSNAME;
            case SERVICE_IMPL:  return BASE_CLASS_NAME+Constant.SERVICE_IMPL_CLASSNAME;
            case CONTROLLER: return BASE_CLASS_NAME+Constant.CONTROLLER_CLASSNAME;
            default:return "";
        }
    }

    /**
     * 根据类型拼接需导入包的列表
     * @param types
     * @return
     */
    public static Set<String> importName(Type... types){
        Set<String> set = new HashSet<>();
        for(Type type: types){
            StringBuilder basePackage = new StringBuilder(Constant.IMPORT+Constant.SPACE+ClassBuilder.BASE_PACKAGE);
            switch (type){
                case DOMAIN:basePackage.append(Constant.DOMAIN_PACKAGE+Constant.DOT+BASE_CLASS_NAME+Constant.DOMAIN_CLASSNAME+Constant.CLOSE);break;
                case DAO:basePackage.append(Constant.DAO_PACKAGE+Constant.DOT+Constant.PREFIX+BASE_CLASS_NAME+Constant.DAO_CLASSNAME+Constant.CLOSE);break;
                case DAO_IMPL:basePackage.append(Constant.DAO_IMPL_PACKAGE+Constant.DOT+BASE_CLASS_NAME+Constant.DAO_IMPL_CLASSNAME+Constant.CLOSE);break;
                case SERVICE:basePackage.append(Constant.SERVICE_PACKAGE+Constant.DOT+Constant.PREFIX+BASE_CLASS_NAME+Constant.SERVICE_CLASSNAME+Constant.CLOSE);break;
                case SERVICE_IMPL:basePackage.append(Constant.SERVICE_IMPL_PACKAGE+Constant.DOT+BASE_CLASS_NAME+Constant.SERVICE_IMPL_CLASSNAME+Constant.CLOSE);break;
                case CONTROLLER:basePackage.append(Constant.CONTROLLER_PACKAGE+Constant.DOT+BASE_CLASS_NAME+Constant.CONTROLLER_CLASSNAME+Constant.CLOSE);break;
                default:basePackage.append("");
            }
            set.add(basePackage.toString());
        }
        return set;
    }

    /**
     * 根据类型拼接类的全限定名
     * @return
     */
    public static String classFullName(Type type){
        StringBuilder basePackage = new StringBuilder(BASE_PACKAGE);
        switch (type){
            case DOMAIN:basePackage.append(Constant.DOMAIN_PACKAGE+Constant.DOT+BASE_CLASS_NAME+Constant.DOMAIN_CLASSNAME);break;
            case DAO:basePackage.append(Constant.DAO_PACKAGE+Constant.DOT+Constant.PREFIX+BASE_CLASS_NAME+Constant.DAO_CLASSNAME);break;
            case DAO_IMPL: basePackage.append(Constant.DAO_IMPL_PACKAGE+Constant.DOT+BASE_CLASS_NAME+Constant.DAO_IMPL_CLASSNAME);break;
            case SERVICE:basePackage.append(Constant.SERVICE_PACKAGE+Constant.DOT+Constant.PREFIX+BASE_CLASS_NAME+Constant.SERVICE_CLASSNAME);break;
            case SERVICE_IMPL:basePackage.append(Constant.SERVICE_IMPL_PACKAGE+Constant.DOT+BASE_CLASS_NAME+Constant.SERVICE_IMPL_CLASSNAME);break;
            case CONTROLLER:basePackage.append(Constant.CONTROLLER_PACKAGE+Constant.DOT+BASE_CLASS_NAME+Constant.CONTROLLER_CLASSNAME);break;
            default:basePackage.append("");
        }
        return basePackage.toString();
    }

    /**
     * 根据类型拼接Java保存路径
     * @return
     */
    public static String pathName(Type type,String moduleName,String path){
        StringBuilder basePackage = new StringBuilder(path);
        basePackage.append("/"+moduleName+"/");
        switch (type){
            case DOMAIN:
                basePackage.append(Constant.DOMAIN_PATH+BASE_CLASS_NAME+Constant.DOMAIN_CLASSNAME+Constant.JAVA_FILE_SUFFIX);
                break;
            case DOMAIN_MAPPING:
                basePackage.append(Constant.DOMAIN_PATH+BASE_CLASS_NAME+Constant.DOMAIN_CLASSNAME+Constant.MAPPING_SUFFIX);
                break;
            case DAO:
                basePackage.append(Constant.DAO_PATH+Constant.PREFIX+BASE_CLASS_NAME+Constant.DAO_CLASSNAME+Constant.JAVA_FILE_SUFFIX);
                break;
            case DAO_IMPL:
                basePackage.append(Constant.DAO_IMPL_PATH+BASE_CLASS_NAME+Constant.DAO_IMPL_CLASSNAME+Constant.JAVA_FILE_SUFFIX);
                break;
            case SERVICE:
                basePackage.append(Constant.SERVICE_PATH+Constant.PREFIX+BASE_CLASS_NAME+Constant.SERVICE_CLASSNAME+Constant.JAVA_FILE_SUFFIX);
                break;
            case SERVICE_IMPL:
                basePackage.append(Constant.SERVICE_IMPL_PATH+BASE_CLASS_NAME+Constant.SERVICE_IMPL_CLASSNAME+Constant.JAVA_FILE_SUFFIX);
                break;
            case CONTROLLER:
                basePackage.append(Constant.CONTROLLER_PATH+BASE_CLASS_NAME+Constant.CONTROLLER_CLASSNAME+Constant.JAVA_FILE_SUFFIX);
                break;
            case FORM:
                basePackage.append(StringUtils.firstToLowerCase(BASE_CLASS_NAME)+Constant.JSP_FORM+Constant.JSP_FILE_SUFFIX);
                break;
            default:
                basePackage.append("");
        }
        return basePackage.toString();
    }

    /**
     * 根据类型拼接保存路径
     * @return
     */
    public static String dirName(Type type,String moduleName,String path){
        StringBuilder basePackage = new StringBuilder(path);
        basePackage.append(moduleName+"/");
        switch (type){
            case DOMAIN:basePackage.append(Constant.DOMAIN_PATH);break;
            case DAO:basePackage.append(Constant.DAO_PATH);break;
            case DAO_IMPL:basePackage.append(Constant.DAO_IMPL_PATH);break;
            case SERVICE:basePackage.append(Constant.SERVICE_PATH);break;
            case SERVICE_IMPL:basePackage.append(Constant.SERVICE_IMPL_PATH);break;
            case CONTROLLER:basePackage.append(Constant.CONTROLLER_PATH);break;
            case DOMAIN_MAPPING:basePackage.append(Constant.DOMAIN);break;
            default:basePackage.append("");
        }
        return basePackage.toString();
    }


    /**
     * 代码生成
     * @param type
     * @param templateFileName
     * @throws Exception
     */
    public static void generateJava(Type type,String templateFileName,String savePath,String tableName,String moduleName,String templateDir){
        try {

            //模块中文拼音名简写
            String moduleSimplePinyin = HanyuPinyinHelper.toHanyuPinyin(moduleName);

            BASE_CLASS_NAME = StringUtils.firstToUpperCase(moduleSimplePinyin);
            TABLE_NAME = tableName;
            BASE_PACKAGE = StringUtils.packageName(savePath,moduleSimplePinyin);
            Configuration cfg = new Configuration(Configuration.VERSION_2_3_23);
            cfg.setDefaultEncoding("UTF-8");

            File loadTemplateFile = null;
            //如果设置面板的模板为空则使用自带模板
            if(Empty.isEmpty(templateDir)){
                templateDir = "template/java/";
                URL url = ClassBuilder.class.getClassLoader().getResource(templateDir);
                //模板加载位置的File对象
                loadTemplateFile = new File(url.toURI());
            }else{
                loadTemplateFile = new File(templateDir);
            }

            cfg.setDirectoryForTemplateLoading(loadTemplateFile);
            cfg.setDefaultEncoding("UTF-8");
            // 路径创建
            File baseDir = new File(savePath);
            if(!baseDir.exists()){
                baseDir.mkdirs();
            }
            File moduleDir = new File(savePath+"/"+moduleSimplePinyin);
            if(!moduleDir.exists()){
                moduleDir.mkdir();
            }
            //将工具类放入模板类
            TemplateHashModel[] utils = useStaticPackage("com.ideal.utils.StringUtils","com.ideal.core.builder.ClassBuilder","com.ideal.core.constant.Type");

            String generateClassPath = pathName(type,moduleSimplePinyin,savePath);
            File path = new File(dirName(type,moduleSimplePinyin,savePath));
            if (!path.exists()) {
                path.mkdirs();
            }
            Writer out1 = new OutputStreamWriter(new FileOutputStream(
                    generateClassPath), "utf-8");
            Template template = cfg.getTemplate(templateFileName);
            Map map = new HashMap(2);
            //StringUtils
            map.put("S",utils[0]);
            //ClassBuilder
            map.put("C",utils[1]);
            //Type
            map.put("T",utils[2]);
            //module
            map.put("module",moduleName);
            map.put("tableName",tableName);
            template.process(map, out1);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }




    /**
     * 代码生成
     * @param type
     * @param templateFileName
     * @throws Exception
     */
    public static void generateJsp(Type type,String templateFileName,String savePath,String tableName,String moduleName,String templateDir){
        try {
            //模块中文拼音名简写
            String moduleSimplePinyin = HanyuPinyinHelper.toHanyuPinyin(moduleName);
            BASE_CLASS_NAME = StringUtils.firstToUpperCase(moduleSimplePinyin);
            TABLE_NAME = tableName;
            Configuration cfg = new Configuration(Configuration.VERSION_2_3_23);
            cfg.setDefaultEncoding("UTF-8");

            File loadTemplateFile = null;
            //如果设置面板的模板为空则使用自带模板
            if(Empty.isEmpty(templateDir)){
                templateDir = "template/jsp/";
                URL url = ClassBuilder.class.getClassLoader().getResource(templateDir);
                //模板加载位置的File对象
                loadTemplateFile = new File(url.toURI());
            }else{
                loadTemplateFile = new File(templateDir);
            }
            cfg.setDirectoryForTemplateLoading(loadTemplateFile);

            // 路径创建
            File baseDir = new File(savePath);
            if(!baseDir.exists()){
                baseDir.mkdirs();
            }
            File moduleDir = new File(savePath+"/"+moduleSimplePinyin);
            if(!moduleDir.exists()){
                moduleDir.mkdir();
            }

            //将工具类放入模板类
            TemplateHashModel[] utils = useStaticPackage("com.ideal.utils.StringUtils","com.ideal.core.builder.ClassBuilder","com.ideal.core.constant.Type");
            String generateJspPath = pathName(type,moduleSimplePinyin,savePath);
            File path = new File(dirName(type,moduleSimplePinyin,savePath));
            if (!path.exists()) {
                path.mkdirs();
            }
            Writer out1 = new OutputStreamWriter(new FileOutputStream(
                    generateJspPath), "utf-8");
            Template template = cfg.getTemplate(templateFileName);
            Map map = new HashMap(2);
            //StringUtils
            map.put("S",utils[0]);
            //ClassBuilder
            map.put("C",utils[1]);
            //Type
            map.put("T",utils[2]);
            //module
            map.put("module",moduleName);
            map.put("tableName",tableName);
            map.put("contextPath","${pageContext.request.contextPath}");
            template.process(map, out1);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 将数据库的相关信息封装到TableClassConverter对象中
     * @return
     * @throws Exception
     */
    public static TableClassConverter tableClass() throws Exception {
        return TableBuilder.tableClass(TABLE_NAME);
    }


    /**
     * 将工具类加到Template中
     * @param packageNames
     * @return
     */
    private static TemplateHashModel[] useStaticPackage(String... packageNames){
        try {
            BeansWrapper wrapper = BeansWrapper.getDefaultInstance();
            TemplateHashModel primary = wrapper.getStaticModels();
            TemplateHashModel[] utils = new TemplateHashModel[packageNames.length];
            for (int i=0;i<packageNames.length;i++){
                utils[i] = (TemplateHashModel) primary.get(packageNames[i]);
            }
            return utils;
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }

}
